using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ScriptBox.Services
{
    public class DBCProcessor
    {
        private readonly string _filePath;
        private readonly int _slotSizeMs;
        private readonly List<MessageInfo> _messages = new List<MessageInfo>();
        private int[] _slots;
        
        private static readonly Regex BoPattern = new Regex(@"^BO_ (\d+) (\w+): \d+ (\w+)$");
        private static readonly Regex CyclePattern = new Regex(@"^BA_ ""GenMsgCycleTime"" BO_ (\d+) (\d+);$");
        private static readonly Regex StartDelayPattern = new Regex(@"^BA_ ""GenMsgStartDelayTime"" BO_ (\d+) (\d+);$");

        // 添加静态构造函数
        static DBCProcessor()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        }
        public DBCProcessor(string filePath, int slotSizeMs = 5)
        {
            _filePath = filePath;
            _slotSizeMs = slotSizeMs;
            InitializeSlots();
        }

        private void InitializeSlots()
        {
            int slotCount = _slotSizeMs == 5 ? 20 : 10;
            _slots = new int[slotCount];
        }

        public void ProcessFile(out string outputPath, out string reportPath)
        {
            ParseDBC();
            CalculateOffsets();
            
            outputPath = GenerateOutputPath();
            reportPath = GenerateReportPath();
            
            GenerateDBC(outputPath);
            GenerateReport(reportPath);
        }

        private void ParseDBC()
        {
            var txMessages = new Dictionary<int, (string Name, string Node)>();
            var cycleTimes = new Dictionary<int, int>();
            var startDelays = new Dictionary<int, int>();

            // 第一次扫描：提取发送报文
            using (var reader = new StreamReader(_filePath, Encoding.GetEncoding("GB2312")))
            {
                while (!reader.EndOfStream)
                {
                    var line = reader.ReadLine();
                    if (line?.StartsWith("BO_ ") == true)
                    {
                        var match = BoPattern.Match(line.Trim());
                        if (match.Success)
                        {
                            var msgId = int.Parse(match.Groups[1].Value);
                            var msgName = match.Groups[2].Value;
                            var node = match.Groups[3].Value;
                            
                            if (node != "Vector__XXX")
                            {
                                txMessages[msgId] = (msgName, node);
                            }
                        }
                    }
                }
            }

            // 第二次扫描：提取周期和延迟时间
            using (var reader = new StreamReader(_filePath, Encoding.GetEncoding("GB2312")))
            {
                while (!reader.EndOfStream)
                {
                    var line = reader.ReadLine()?.Trim();
                    if (string.IsNullOrEmpty(line)) continue;

                    if (line.StartsWith("BA_ \"GenMsgCycleTime\""))
                    {
                        var match = CyclePattern.Match(line);
                        if (match.Success)
                        {
                            var msgId = int.Parse(match.Groups[1].Value);
                            var cycle = int.Parse(match.Groups[2].Value);
                            cycleTimes[msgId] = cycle;
                        }
                    }
                    else if (line.StartsWith("BA_ \"GenMsgStartDelayTime\""))
                    {
                        var match = StartDelayPattern.Match(line);
                        if (match.Success)
                        {
                            var msgId = int.Parse(match.Groups[1].Value);
                            var delay = int.Parse(match.Groups[2].Value);
                            startDelays[msgId] = delay;
                        }
                    }
                }
            }

            // 修改原来的赋值方式
            _messages.Clear();  // 先清空列表
            _messages.AddRange(  // 使用AddRange代替直接赋值
                txMessages
                    .Where(kv => cycleTimes.ContainsKey(kv.Key))
                    .Select(kv => new MessageInfo
                    {
                        Id = kv.Key,
                        Name = kv.Value.Name,
                        Cycle = cycleTimes.TryGetValue(kv.Key, out var ct) ? ct : (int?)null,
                        ExistingDelay = startDelays.TryGetValue(kv.Key, out var sd) ? sd : (int?)null
                    })
            );
        }

        private void CalculateOffsets()
        {
            var sortedMsgs = _messages
                .Where(m => m.Cycle.HasValue)
                .OrderBy(m => m.Cycle)
                .ThenBy(m => m.Id)
                .ToList();

            foreach (var msg in sortedMsgs)
            {
                var cycle = msg.Cycle.Value;
                var slotCount = _slots.Length;

                if (cycle < 100)
                {
                    int requiredSlots = 100 / cycle;
                    int step = cycle / _slotSizeMs;
                    int minLoad = int.MaxValue;
                    int bestStart = 0;

                    for (int slot = 0; slot < slotCount; slot++)
                    {
                        int totalLoad = 0;
                        for (int i = 0; i < requiredSlots; i++)
                        {
                            totalLoad += _slots[(slot + i * step) % slotCount];
                        }

                        if (totalLoad < minLoad)
                        {
                            minLoad = totalLoad;
                            bestStart = slot;
                        }
                    }

                    msg.Offset = bestStart * _slotSizeMs;
                    for (int i = 0; i < requiredSlots; i++)
                    {
                        int slot = (bestStart + i * step) % slotCount;
                        _slots[slot]++;
                    }
                }
                else
                {
                    var minSlot = Enumerable.Range(0, slotCount)
                        .OrderBy(i => _slots[i])
                        .First();

                    msg.Offset = minSlot * _slotSizeMs;
                    _slots[minSlot]++;
                }
            }
        }

        private void GenerateDBC(string outputPath)
        {
            var offsetMap = _messages
                .Where(m => m.Offset != 0)
                .ToDictionary(m => m.Id, m => m.Offset);

            // 使用GBK编码读写DBC文件
            using (var reader = new StreamReader(_filePath, Encoding.GetEncoding("GB2312")))
            using (var writer = new StreamWriter(outputPath, false, Encoding.GetEncoding("GB2312")))
            {
                string currentLine;
                while ((currentLine = reader.ReadLine()) != null)
                {
                    var line = currentLine.Trim();
                    var originalLine = currentLine;

                    // 处理BO_行
                    if (Regex.IsMatch(originalLine, @"^\s*BO_ "))
                    {
                        var match = BoPattern.Match(line);
                        if (match.Success)
                        {
                            writer.WriteLine(originalLine);
                            continue;
                        }
                    }

                    // 处理周期时间属性
                    if (Regex.IsMatch(originalLine, @"^\s*BA_ ""GenMsgCycleTime"""))
                    {
                        var match = CyclePattern.Match(line);
                        if (match.Success && int.TryParse(match.Groups[1].Value, out var msgId))
                        {
                            writer.WriteLine(originalLine);
                            if (offsetMap.TryGetValue(msgId, out var offset))
                            {
                                writer.WriteLine($"BA_ \"GenMsgStartDelayTime\" BO_ {msgId} {offset};");
                            }
                            continue;
                        }
                    }

                    // 处理已有延迟时间
                    if (Regex.IsMatch(originalLine, @"^\s*BA_ ""GenMsgStartDelayTime"""))
                    {
                        var match = StartDelayPattern.Match(line);
                        if (match.Success && int.TryParse(match.Groups[1].Value, out var msgId))
                        {
                            if (offsetMap.TryGetValue(msgId, out var offset))
                            {
                                writer.WriteLine($"BA_ \"GenMsgStartDelayTime\" BO_ {msgId} {offset};");
                            }
                            continue;
                        }
                    }

                    writer.WriteLine(originalLine);
                }
            }
        }

        private void GenerateReport(string reportPath)
        {
            var sortedMsgs = _messages
                // 移除偏移量过滤
                .OrderBy(m => m.Cycle)
                .ThenBy(m => m.Id)
                .ToList();

            using (var writer = new StreamWriter(reportPath))
            {
                writer.WriteLine("# DBC报文偏移时间分配报告\n");
                writer.WriteLine("| 报文ID | 报文名称 | 周期(ms) | 偏移时间(ms) |");
                writer.WriteLine("|--------|----------|----------|-------------|");

                foreach (var msg in sortedMsgs)
                {
                    writer.WriteLine($"| {msg.Id} | {msg.Name} | {msg.Cycle} | {msg.Offset} |");
                }
            }
        }

        private string GenerateOutputPath()
        {
            string slotSuffix = _slotSizeMs == 10 ? "_10ms" : "";
            return Path.Combine(
                Path.GetDirectoryName(_filePath),
                $"{Path.GetFileNameWithoutExtension(_filePath)}{slotSuffix}_modified.dbc"
            );
        }

        private string GenerateReportPath()
        {
            return Path.Combine(
                Path.GetDirectoryName(_filePath),
                $"{Path.GetFileNameWithoutExtension(_filePath)}_report.md"
            );
        }

        private class MessageInfo
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int? Cycle { get; set; }
            public int? ExistingDelay { get; set; }
            public int Offset { get; set; }
        }
    }
}